﻿using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;

namespace ButtonBuilder.Controls
{
    public class Page : IEnumerable<Button>
    {
        public event PropertyChangedEventHandler PropertyChanged;

        #region Private Properties
        private List<Button> _buttons;
        private Button _buttonInFocus;
        #endregion

        #region Constructors
        public Page(string name) 
        {
            _buttons = new List<Button>();

            Name = name;
            Background = "Transparent";
            Dirty = true;
            Created = true;
        }

        public Page(Data.Page page)
        {
            Name = page.Name;
            ImageVisible = page.ImageVisible;
            ImagePath = page.ImagePath;
            Background = page.Background;
            Location = page.Location;
            Size = page.Size;
            ShowOnStartup = page.ShowOnStartup;

            _buttons = new List<Button>();

            foreach (Data.Button buttonData in page.Buttons)
            {
                Controls.Button button = (Controls.Button)System.Activator.CreateInstance(
                    System.Reflection.Assembly.GetEntryAssembly().FullName,
                    buttonData.ButtonType).Unwrap();

                button.SetData(buttonData);
                Canvas.SetTop(button, buttonData.Top);
                Canvas.SetLeft(button, buttonData.Left);
                Canvas.SetZIndex(button, buttonData.ZIndex);

                Add(button, false);
            }

            Created = true;
        }
        #endregion

        #region Properties
        private bool Created { get; set; }

        public bool Dirty { get; set; }

        public string Name { get; set; }

        public bool ImageVisible { get; set; }

        public string ImagePath { get; set; }

        public string Background { get; set; }

        public string Location { get; set; }

        public string Size { get; set; }

        public bool ShowOnStartup { get; set; }

        public List<Button> Buttons
        {
            get { return _buttons; }
            set { _buttons = value; }
        }
        #endregion

        #region List Functions
        public void Add(Button buttonControl, bool newButton = true)
        {
            if (newButton)
            {
                int maxZIndex = _buttons.Count == 0 ? 0 : _buttons.Max(b => Canvas.GetZIndex(b));
                int maxTabIndex = _buttons.Count == 0 ? 0 : _buttons.Max(b => b.TabIndex);

                Canvas.SetZIndex(buttonControl, maxZIndex + 1);
                buttonControl.TabIndex = maxTabIndex + 1;
            }

            buttonControl.Page = this;
            buttonControl.PropertyChanged += new PropertyChangedEventHandler(ButtonPropertyChanged);
            buttonControl.Unloaded += new RoutedEventHandler(ButtonUnloaded);
            buttonControl.GotFocus += new RoutedEventHandler(ButtonGotFocus);

            _buttons.Add(buttonControl);

            if (Created)
                OnPropertyChanged("Buttons");            
        }
        #endregion

        #region Button Events
        private void ButtonGotFocus(object sender, RoutedEventArgs e)
        {
            if (_buttonInFocus != null)
            {
                //Deselect Previous
                _buttonInFocus.Border.BorderBrush = new SolidColorBrush(Colors.Black);
                _buttonInFocus.Border.BorderThickness = new Thickness(1);
            }

            _buttonInFocus = (Button)sender;
            _buttonInFocus.Border.BorderBrush = new SolidColorBrush(Colors.Yellow);
            _buttonInFocus.Border.BorderThickness = new Thickness(2);
        }

        private void ButtonUnloaded(object sender, RoutedEventArgs e)
        {
            ((Button)sender).Dispose();
        }

        private void ButtonPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            OnPropertyChanged(e.PropertyName);
        }
        #endregion

        #region Page Functions
        protected void OnPropertyChanged(string name)
        {
            Dirty = true;
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(name));
        }

        public void DeleteFile()
        {
            Data.Repository.DeletePageFile(Name);
        }

        public void Save()
        {
            Dirty = false;
            Data.Repository.SavePage(GetData());
        }

        private Data.Page GetData()
        {
            Data.Page page = new Data.Page() 
            { 
                Name = this.Name,
                ImageVisible = this.ImageVisible,
                ImagePath = this.ImagePath,
                Background = this.Background,
                Location = this.Location,
                Size = this.Size,
                ShowOnStartup = this.ShowOnStartup
            };

            foreach (Button b in _buttons)
            {
                page.Buttons.Add(b.GetData());
            }

            return page;
        }

        public void RaiseButton(UIElement toRaise)
        {
            //Lower z-index of all elements by 1
            foreach (Button b in _buttons)
            {
                Canvas.SetZIndex(b, Canvas.GetZIndex(b) - 1);
            }

            Canvas.SetZIndex(toRaise, Canvas.GetZIndex(toRaise) + 2);

            NormalizeZLayer();
        }

        public void LowerButton(UIElement toLower)
        {
            //Raise z-index of all elements by 1
            foreach (Button b in _buttons)
            {
                Canvas.SetZIndex(b, Canvas.GetZIndex(b) + 1);
            }

            Canvas.SetZIndex(toLower, Canvas.GetZIndex(toLower) - 2);

            NormalizeZLayer();
        }

        private void NormalizeZLayer()
        {
            int zStart = 0;

            List<Button> buttonsOrderedByZIndex = _buttons.OrderBy(b => Canvas.GetZIndex(b)).ToList();

            foreach (Button b in buttonsOrderedByZIndex)
            {
                Canvas.SetZIndex(b, ++zStart);
            }
        }

        private void NormalizeTabIndex()
        {
            int tStart = 0;

            List<Button> buttonsOrderedByTabIndex = _buttons.OrderBy(b => b.TabIndex).ToList();

            foreach (Button b in buttonsOrderedByTabIndex)
            {
                b.TabIndex = ++tStart;
            }
        }

        public void Remove(Button button)
        {
            Buttons.Remove(button);
            
            NormalizeZLayer();
            NormalizeTabIndex();

            OnPropertyChanged("Buttons");
        }
        #endregion
                
        #region Object Overrides
        public override bool Equals(object obj)
        {
            //Check for null and compare run-time types.
            if (obj == null || GetType() != obj.GetType()) 
                return false;
            
            Page p = (Page)obj;

            return p.Name.Equals(this.Name);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        public override string ToString()
        {
            return string.Format("Name = {0}", Name);
        }
        #endregion
        
        #region IEnumerable<Button> Members

        public IEnumerator<Button> GetEnumerator()
        {
            return (_buttons as IEnumerable<Button>).GetEnumerator();
        }

        #endregion

        #region IEnumerable Members

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return (_buttons as IEnumerable<ActionButton>).GetEnumerator();
        }

        #endregion

    }
}
